#ifndef Scheduler_h
#define Scheduler_h

#include "TaskPriority.h"

#include <map>

namespace serika
{
	namespace ut
	{
		class Clock;
		class TaskTrigger;
		class Task;

		class Scheduler
		{
		public:
			Scheduler();
			~Scheduler();

		public:
			static Scheduler* Instance();

		public:
			void ExecuteTask(const Clock& clock);

			int ScheduleEveryFrameTask(Task* task, TaskPriority::Enum priority = TaskPriority::Medium);
			int ScheduleRepeatedTimeTask(Task* task, size_t loopInterval, TaskPriority::Enum priority = TaskPriority::Medium);
			int ScheduleOnceTimeTask(Task* task, size_t start, TaskPriority::Enum priority = TaskPriority::Medium);
			int ScheduleOnceFrameTask(Task* task, size_t start, TaskPriority::Enum priority = TaskPriority::Medium);
			int ScheduleFrameTask(Task* task,
				size_t start, size_t end, size_t loopInterval,
				TaskPriority::Enum priority = TaskPriority::Medium);
			int ScheduleTimeTask(Task* task,
				size_t start, size_t end, size_t loopInterval,
				TaskPriority::Enum priority = TaskPriority::Medium);

			void TerminateTask(int id);
			void TerminateTask(Task* task);

		private:
			struct TaskInfo
			{
				TaskTrigger* trigger;
				Task* task;
				bool deleted;
			};

			typedef std::map<int, TaskInfo*> InfoList; // map<id, taskInfo*>
			typedef std::map<TaskPriority::Enum, InfoList> InfoMap; // map<priority, infoList>
			InfoMap mInfoMap;

			typedef std::map<int, int> IdPriorityMap; // map<id, priority>
			IdPriorityMap mIdPriorityMap;

			int mIdSeed;

		private:
			int GetId() { return ++mIdSeed; }
			InfoList& GetInfoList(TaskPriority::Enum priority);

			template <class Trigger>
			int ScheduleTask(Task* task,
				size_t start, size_t end, size_t loopInterval,
				TaskPriority::Enum priority);

			TaskInfo* NewInfo(Task* task, TaskTrigger* trigger);
			void DeleteInfo(TaskInfo* info);

			void Execute(TaskInfo* info, int id, const Clock& clock);
		};
	}
}

#endif
